/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package custom.swing;

import javax.swing.AbstractListModel;
import javax.swing.MutableComboBoxModel;
import java.io.Serializable;
import java.util.List;
import java.util.LinkedList;
import java.util.Set;
import java.util.LinkedHashSet;

/**
 *
 * @author david
 */
public class UniqueStackComboBoxModel extends AbstractListModel implements MutableComboBoxModel, Serializable {

    private List objects = null;
    private Object selectedObject = null;

    public UniqueStackComboBoxModel() {
        objects = new LinkedList();
    }

    public UniqueStackComboBoxModel(final Object[] items) {
        this();
        if(items != null && items.length > 0) {
        objects.addAll(pruneDups(items));
            if (getSize() > 0) {
                selectedObject = getElementAt(0);
            }
        }
    }

    // Ensure that all items in the array are not dups by putting them in a set.
    private Set<?> pruneDups(final Object[] items) {
        Set set = null;

        if (items != null && items.length > 0) {
            set = new LinkedHashSet(items.length);
            for (Object o : items) {
                set.add(o);
            }
        }

        return set;
    }

    // This method sets the selected item without adding the value to the list.
    public void setSelectedItem(Object anObject) {
        if ((selectedObject != null && !selectedObject.equals(anObject)) ||
                selectedObject == null && anObject != null) {
            selectedObject = anObject;
            fireContentsChanged(this, -1, -1);
            // See if this object is in the list.
            int idx = objects.indexOf(anObject);
            if (idx > 0) {
                // This object is in the list and is not at the top. Move it to the top.
                objects.remove(idx);
                objects.add(0, anObject);
            }
        }
    }

    public Object getSelectedItem() {
        return selectedObject;
    }

    public int getSize() {
        return objects.size();
    }

    public Object getElementAt(int index) {
        Object element = null;
        if (index >= 0 && index < objects.size()) {
            element = objects.get(index);
        }
        return element;
    }

    public int getIndexOf(Object anObject) {
        return objects.indexOf(anObject);
    }

    // This will always add to the beginning of the list.
    public void addElement(Object anObject) {
        // If object is already in the list and is not at the beginning, remove it from the list.
        int idx = objects.indexOf(anObject);
        switch (idx) {
            default:
                // idx is greater than 0, so the object is already in the list and not at the
                // beginning. Remove it from the list.
                objects.remove(anObject);
            // Fall through on purpose so that we will add the object to the list at the beginning.
            case -1:
                // If idx is -1, this object is not in the list. Add it to the beginning.
                objects.add(0, anObject);
                break;

            case 0:
                // If idx is 0, the object is already in the list and is at the beginning, so take no action.
                break;
        }

        fireIntervalAdded(this, objects.size() - 1, objects.size() - 1);
        // Select the item we just added.
        setSelectedItem(anObject);
    }

    // This method will override the behavior of this class to add everything to the beginning of the list.
    public void insertElementAt(Object anObject, int index) {
        // If object is already in the list, remove it from the list.
        int idx;
        if ((idx = objects.indexOf(anObject)) > -1) {
            objects.remove(anObject);
        }
        // Now, insert it.
        objects.add(index, anObject);
        fireIntervalAdded(this, index, index);
        setInsertedSelectedItem(anObject);
    }

    private void setInsertedSelectedItem(Object anObject) {
        if ((selectedObject != null && !selectedObject.equals(anObject)) ||
                selectedObject == null && anObject != null) {
            selectedObject = anObject;
            fireContentsChanged(this, -1, -1);
        }
    }

    public void removeElementAt(int index) {
        if (getElementAt(index) == selectedObject) {
            objects.remove(index);
            if (index == 0) {
                //setSelectedItem( getSize() == 1 ? null : getElementAt( index + 1 ) );
                setSelectedItem(getSize() == 0 ? null : getElementAt(index));
            } else {
                setSelectedItem(getElementAt(index - 1));
            }
            fireIntervalRemoved(this, index, index);
        }
    }

    public void removeElement(Object anObject) {
        int index = objects.indexOf(anObject);
        if (index != -1) {
            removeElementAt(index);
        }
    }

    public void removeAllElements() {
        if (objects.size() > 0) {
            int firstIndex = 0;
            int lastIndex = objects.size() - 1;
            objects.clear();
            selectedObject = null;
            fireIntervalRemoved(this, firstIndex, lastIndex);
        } else {
            selectedObject = null;
        }
    }
}
